package role

import (
	"sanguo/cluster"
	"sanguo/node/common/aoi"
	"sanguo/node/node_map"
	"sanguo/node/node_map/scene"
	cs_message "sanguo/protocol/cs/message"
	ss_message "sanguo/protocol/ss/message"

	"github.com/golang/protobuf/proto"
	"github.com/sniperHW/kendynet"
)

//如果this可以看见o返回true,否则返回false
func (this *Role) CheckVisiable(o *Role) bool {
	sceneStoryStage := this.Scene.GetStoryStage(this.StoryStage)
	if nil == sceneStoryStage {
		return true
	} else {
		if int32(o.StoryStage) >= sceneStoryStage.Min && int32(o.StoryStage) <= sceneStoryStage.Max {
			return true
		} else {
			return false
		}
	}
}

func (this *Role) OnEnterScene() {

	if len(this.enter) > 0 {

		node_map.Infoln(this.Name, "enterScene")
		//请求视野目标将信息发送给自己
		EnterSeeToC := &cs_message.EnterSeeToC{
			Objs: make([]*cs_message.ViewObj, 100)[0:0],
		}
		EnterSeeToC.Objs = append(EnterSeeToC.Objs, this.PackRoleData())

		for o, _ := range this.enter {
			if o != this {
				EnterSeeToC.Objs = append(EnterSeeToC.Objs, o.PackRoleData())
				if len(EnterSeeToC.Objs) == 100 {
					this.SendToClient(EnterSeeToC)
					EnterSeeToC.Objs = EnterSeeToC.Objs[0:0]
				}
			}
		}

		if len(EnterSeeToC.Objs) > 0 {
			this.SendToClient(EnterSeeToC)
		}

		this.enter = map[*Role]bool{}
	}
}

func (this *Role) SendEnterSee() {

	if len(this.enter) > 0 {

		node_map.Infoln(this.UserID, "SendEnterSee", len(this.enter))

		EnterSeeToC := &cs_message.EnterSeeToC{
			Objs: make([]*cs_message.ViewObj, 100)[0:0],
		}

		for o, _ := range this.enter {
			if o != this {
				node_map.Infoln(this.UserID, "SendEnterSee1", o.UserID)
				EnterSeeToC.Objs = append(EnterSeeToC.Objs, o.PackRoleData())
				if len(EnterSeeToC.Objs) == 100 {
					this.SendToClient(EnterSeeToC)
					node_map.Infoln(this.UserID, "SendEnterSee2")
					EnterSeeToC.Objs = EnterSeeToC.Objs[0:0]
				}
			}
		}

		if len(EnterSeeToC.Objs) > 0 {
			node_map.Infoln(this.UserID, "SendEnterSee3")
			this.SendToClient(EnterSeeToC)
		}

		this.enter = map[*Role]bool{}

	}
}

func (this *Role) SendLeaveSee() {
	if len(this.leave) > 0 {
		LeaveSeeToC := &cs_message.LeaveSeeToC{
			RoleID: make([]uint64, 200)[0:0],
		}

		for o, _ := range this.leave {
			if o != this {
				LeaveSeeToC.RoleID = append(LeaveSeeToC.RoleID, o.ID)
				if len(LeaveSeeToC.RoleID) == 200 {
					this.SendToClient(LeaveSeeToC)
					LeaveSeeToC.RoleID = LeaveSeeToC.RoleID[0:0]
				}
			}
		}

		if len(LeaveSeeToC.RoleID) > 0 {
			this.SendToClient(LeaveSeeToC)
		}

		this.leave = map[*Role]bool{}
	}
}

func (this *Role) OnLeaveScene() {
	node_map.Infoln(this.Name, "leaveScene")
}

func (this *Role) IsAoiObject() bool {
	return true
}

func (this *Role) SetAoiPosition(pos aoi.Position) {
	this.AoiPos = pos
}

func (this *Role) GetAoiPosition() *aoi.Position {
	return &this.AoiPos
}

func (this *Role) GetGrid() *aoi.Grid {
	return this.Grid
}

func (this *Role) SetGrid(grid *aoi.Grid) {
	this.Grid = grid
}

func (this *Role) AddObserver(o aoi.AOIObject) {

	if !this.CheckVisiable(o.(*Role)) {
		return
	}

	if _, ok := this.Observers[o]; ok {
		//node_map.Errorln("duplicate AddObserver")
		return
	}
	this.Observers[o] = true
	this.enter[o.(*Role)] = true
	node_map.Infof("enterSee %s enter %s", this.UserID, o.(*Role).UserID)
	delete(this.leave, o.(*Role))
}

func (this *Role) RemoveObserver(o aoi.AOIObject) {

	/*if !this.CheckVisiable(o.(*Role)) {
		return
	}*/

	if _, ok := this.Observers[o]; !ok {
		//node_map.Errorln("invaild observer")
		return
	}
	delete(this.Observers, o)
	node_map.Infof("leaveSee %s leave %s", this.UserID, o.(*Role).UserID)
	this.leave[o.(*Role)] = true
	delete(this.enter, o.(*Role))
}

func (this *Role) ForEachObserver(cb func(aoi.AOIObject)) {
	for o, _ := range this.Observers {
		//if this.GetID() != o.(*Role).GetID() {
		cb(o)
		//}

	}
}

func (this *Role) ClearObjserver() {
	this.Observers = map[aoi.AOIObject]bool{}
}

func (this *Role) OnAoiUpdate() {

}

func (this *Role) OnStoryStageChange(storyStage int64) {

	this.StoryStage = storyStage

	//StoryStage的改变可能会改变AOI
	for o, _ := range this.Observers {
		if this != o.(*Role) && !this.CheckVisiable(o.(*Role)) {
			//原来可见，现在不可见，需要出发leavesee
			if _, ok := this.Observers[o]; ok {
				delete(this.Observers, o)
				node_map.Infof("leaveSee %s leave %s", this.UserID, o.(*Role).UserID)
				this.leave[o.(*Role)] = true
				delete(this.enter, o.(*Role))
				o.RemoveObserver(this)
			}
		}
	}

	viewObjs := this.Scene.GetViewObjs(this)

	if nil == viewObjs {
		return
	}

	for _, o := range viewObjs {
		if o.(*Role) != this && this.CheckVisiable(o.(*Role)) {
			if _, ok := this.Observers[o]; !ok {
				this.Observers[o] = true
				this.enter[o.(*Role)] = true
				node_map.Infof("enterSee %s enter %s", this.UserID, o.(*Role).UserID)
				delete(this.leave, o.(*Role))
				o.AddObserver(this)
			}
		}
	}
}

func onStartAoi(session kendynet.StreamSession, msg proto.Message) {
	req := msg.(*ss_message.StartAoi)

	scene_ := scene.GetSceneByType(scene.SceneType(req.GetMapType()))
	if nil == scene_ {
		return
	}

	scene_.PostTask(func() {
		sceneO := scene_.GetObjByID(req.GetUserID())
		scene_.StartAoi(sceneO)
	})
}

func onStoryStageChange(session kendynet.StreamSession, msg proto.Message) {
	req := msg.(*ss_message.OnStoryStageChange)

	scene_ := scene.GetSceneByType(scene.SceneType(req.GetMapType()))
	if nil == scene_ {
		return
	}

	scene_.PostTask(func() {
		sceneO := scene_.GetObjByID(req.GetUserID())
		storyStage := req.GetStoryStage()
		sceneO.(*Role).OnStoryStageChange(storyStage)
	})
}

func init() {
	cluster.Register(&ss_message.OnStoryStageChange{}, onStoryStageChange)
	cluster.Register(&ss_message.StartAoi{}, onStartAoi)
}
